package com.sc.demo.plugins;

import java.lang.reflect.Method;
import java.util.Properties;

import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.log4j.Logger;

import com.sc.demo.annotation.Master;


@Intercepts({
	@Signature(type = Executor.class, method = "query", args = { MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
	@Signature(type = Executor.class, method = "query", args = { MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class})
})
public class MasterSlaveRouterPlugin implements Interceptor {
	
	
	private Logger logger = Logger.getLogger(MasterSlaveRouterPlugin.class);
	
	public Object intercept(Invocation invocation) throws Throwable {
		String sqlId = ((MappedStatement)invocation.getArgs()[0]).getId();
		logger.debug("[MasterSlaveRouterPlugin] Class   = " + sqlId.substring(0, sqlId.lastIndexOf('.')));
		logger.debug("[MasterSlaveRouterPlugin] Method  = " + ((MappedStatement)invocation.getArgs()[0]).getId());
		String daoClassName = sqlId.substring(0, sqlId.lastIndexOf('.'));
		String methodName = sqlId.substring(sqlId.lastIndexOf('.'));
		
		boolean isMaster = false;
		Method[] methods= Class.forName(daoClassName).getMethods();
		for(Method method : methods){
			if(method.getName().equals(methodName)){
				Master master = method.getAnnotation(Master.class);
				if(master != null){
					isMaster = true;
					break;
				}
			}
		}
		//切换到从库
		((Executor)invocation.getTarget()).getTransaction().getConnection().setReadOnly(isMaster);
		Object o = invocation.proceed();
		//切换回主库，防止写操作失败
		((Executor)invocation.getTarget()).getTransaction().getConnection().setReadOnly(false);
		return o;
	}

	public Object plugin(Object target) {
		return Plugin.wrap(target, this);
	}

	public void setProperties(Properties properties) {
	}
}
